import logging

import pandas as pd

from util.log_util import get_the_logger
logger = get_the_logger(__name__)

# 辅助函数：处理空结果
def empty_result(start, end):
    return {
        "开始时间": start.strftime('%Y-%m-%d') if start else "",
        "结束时间": end.strftime('%Y-%m-%d') if end else "",
        "总投入": 0,
        "最终资产": 0,
        "总利润": 0,
        "总收益率": 0,
        "年化收益率": 0,
        "买入次数": 0,
        "买入记录": []
    }


# 处理开始和结束时间
def process_dates(df, start_date, end_date):
    if start_date is not None:
        start_date = pd.to_datetime(start_date)
    if end_date is not None:
        end_date = pd.to_datetime(end_date)
    if start_date is None or start_date < df.index[0]:
        start_date = df.index[0]
    if end_date is None or end_date > df.index[-1]:
        end_date = df.index[-1]
    return start_date, end_date


# 定投：下跌就以一定的比例k 加倍买入
def gambling_daily_invest(df, money, k=1.1, start_date=None, end_date=None):
    start_date, end_date = process_dates(df, start_date, end_date)
    # 初始化总投入、总收益、总份额
    total_cost = 0
    total_gain = 0
    total_units = 0
    # 初始定投金额
    base_investment = money
    current_investment = money
    # 记录上一天的单位净值
    prev_net_value = None

    # 筛选出指定日期范围内的数据
    df_range = df[(df.index >= start_date) & (df.index <= end_date)]

    # 进行定投操作
    for index, row in df_range.iterrows():
        net_value = row['单位净值']
        if prev_net_value is not None:
            if net_value < prev_net_value:
                # 价格下跌，增加投入
                current_investment *= k
            else:
                # 价格止跌，恢复初始投入
                current_investment = base_investment
        # 计算当天购买的份额
        daily_units = current_investment / net_value
        total_units += daily_units
        total_cost += current_investment
        prev_net_value = net_value

    # 计算最后一天的资产价值
    if not df_range.empty:
        last_net_value = df_range['单位净值'].iloc[-1]
        final_asset = total_units * last_net_value + total_gain
    else:
        final_asset = 0

    # 计算总收益和收益率
    total_profit = final_asset - total_cost
    total_return_rate = total_profit / total_cost if total_cost != 0 else 0

    # 计算投资天数
    investment_days = (end_date - start_date).days
    # 计算年化收益率
    if total_cost != 0 and investment_days > 0:
        annual_return_rate = ((final_asset / total_cost) ** (365 / investment_days)) - 1
    else:
        annual_return_rate = 0

    return {
        "开始时间": start_date.strftime('%Y-%m-%d'),
        "结束时间": end_date.strftime('%Y-%m-%d'),
        "总投入（买基金花费）": total_cost,
        "总收益（卖基金所得）": total_gain,
        "最终持有基金份额": total_units,
        "最终资产": final_asset,
        "总利润": total_profit,
        "总收益率": total_return_rate,
        "年化收益率": annual_return_rate
    }


# 定投：涨了和跌了买不同金额的
def variable_invest(df, buy_when_down, buy_when_up, start_date=None, end_date=None):
    start_date, end_date = process_dates(df, start_date, end_date)
    # 初始化总投入、总收益、总份额
    total_cost = 0
    total_gain = 0
    total_units = 0
    # 记录上一天的单位净值
    prev_net_value = None

    # 筛选出指定日期范围内的数据
    df_range = df[(df.index >= start_date) & (df.index <= end_date)]

    # 进行定投操作
    for index, row in df_range.iterrows():
        net_value = row['单位净值']
        if prev_net_value is not None:
            if net_value < prev_net_value:
                # 价格下跌，买入 buy_when_down 元
                daily_units = buy_when_down / net_value
                total_units += daily_units
                total_cost += buy_when_down
            else:
                # 价格上涨，买入 buy_when_up 元
                daily_units = buy_when_up / net_value
                total_units += daily_units
                total_cost += buy_when_up
        prev_net_value = net_value

    # 计算最后一天的资产价值
    if not df_range.empty:
        last_net_value = df_range['单位净值'].iloc[-1]
        final_asset = total_units * last_net_value
    else:
        final_asset = 0

    # 计算总收益和收益率
    total_profit = final_asset - total_cost
    total_return_rate = total_profit / total_cost if total_cost != 0 else 0

    # 计算投资天数
    investment_days = (end_date - start_date).days
    # 计算年化收益率
    if total_cost != 0 and investment_days > 0:
        annual_return_rate = ((final_asset / total_cost) ** (365 / investment_days)) - 1
    else:
        annual_return_rate = 0

    return {
        "开始时间": start_date.strftime('%Y-%m-%d'),
        "结束时间": end_date.strftime('%Y-%m-%d'),
        "总投入（买基金花费）": total_cost,
        "总收益（卖基金所得）": total_gain,
        "最终持有基金份额": total_units,
        "最终资产": final_asset,
        "总利润": total_profit,
        "总收益率": total_return_rate,
        "年化收益率": annual_return_rate,
        "买入次数": "ALL"
    }


# 均值策略变体：
# 参数k是一个大于等于1的常数
# 仍然是在当天的价格低于某天数的均线时，进行买入y元
# 还要计算当天的价格减去前一天价格，差值为当天的delta
# 如果delta一直在变小，就不断给y乘上k，进行买入
# 如果delta一直在变大，就累除k，直到y变回了原来的初始值，就不能再让它变小了
def strategy_based_on_mean_and_diff(df, y=200, days=30, k=1.0, start_date=None, end_date=None):
    """
    均值策略改进版：结合价格变化趋势动态调整买入金额
    核心逻辑：
    1. 当价格低于均线时买入
    2. 根据价格变化方向（delta）调整买入金额：
       - 如果delta持续减小，买入金额按k倍递增
       - 如果delta持续增大，买入金额按k倍递减（最低为初始y值）

    :param df: 基金净值数据（需包含日期索引和'单位净值'列）
    :param y: 基础买入金额
    :param days: 均线计算窗口
    :param k: 金额调整倍数（必须 >1）
    :param start_date: 策略开始日期
    :param end_date: 策略结束日期
    :return: 包含收益指标的字典
    """

    # --- 初始化 ---
    start_date, end_date = process_dates(df, start_date, end_date)
    total_cost = 0
    total_units = 0
    attempts_times = 0

    # 获取日期索引位置
    start_index = df.index.searchsorted(start_date)
    end_index = df.index.searchsorted(end_date)

    # 确保至少能计算均线和价格变化（前一天数据）
    start_index = max(start_index, days, 1)  # 需满足：均线窗口 + delta计算
    if start_index >= end_index:
        return empty_result(start_date, end_date)

    # --- 核心逻辑 ---
    df_range = df.iloc[start_index:end_index]
    current_multiplier = 1.0  # 当前金额乘数（初始为1倍）
    previous_delta = None  # 前一日价格变化量

    for i in range(len(df_range)):
        # 获取当前数据位置
        current_pos = start_index + i
        current_net_value = df['单位净值'].iloc[current_pos]

        # 计算均线（从原始数据切片保证窗口正确）
        last_days_mean = df['单位净值'].iloc[current_pos - days: current_pos].mean()

        # 计算delta（当天净值 - 前一天净值）
        prev_net_value = df['单位净值'].iloc[current_pos - 1]
        delta = current_net_value - prev_net_value

        # 仅当价格低于均线时买入
        if current_net_value > last_days_mean:
            previous_delta = delta  # 记录delta用于下次比较
            continue

        # # --- 动态调整买入金额 ---
        # if previous_delta is not None:  # 从第二次买入开始调整
        #     # 判断价格波动趋势
        #     if abs(delta) < abs(previous_delta):
        #         current_multiplier *= k  # 波动减小：激进加仓
        #     else:
        #         current_multiplier /= k  # 波动增大：保守减仓
        #         current_multiplier = max(current_multiplier, 1.0)  # 不低于初始值


        # 改进点：仅在价格下跌且波动减小时加仓
        if previous_delta is not None:
            if delta < 0 and abs(delta) < abs(previous_delta):
                current_multiplier *= k
                # logger.info(f"加仓: 日期={df.index[current_pos]}, 乘数={current_multiplier:.2f}")  # 日志
            else:
                current_multiplier = max(current_multiplier / k, 1.0)

        # 买入操作
        investment = y * current_multiplier
        daily_units = investment / current_net_value
        total_units += daily_units
        total_cost += investment
        attempts_times += 1

        # 保存当前delta供下次比较
        previous_delta = delta

    # --- 收益计算（保持原有逻辑）---
    if not df_range.empty:
        last_net_value = df_range['单位净值'].iloc[-1]
        final_asset = total_units * last_net_value
    else:
        final_asset = 0

    total_profit = final_asset - total_cost
    total_return_rate = total_profit / total_cost if total_cost != 0 else 0
    investment_days = (end_date - start_date).days

    # 年化收益率（保持原有复利公式）
    if total_cost != 0 and investment_days > 0:
        annual_return_rate = (final_asset / total_cost) ** (365 / investment_days) - 1
    else:
        annual_return_rate = 0

    return {
        "开始时间": start_date.strftime('%Y-%m-%d'),
        "结束时间": end_date.strftime('%Y-%m-%d'),
        "总投入（买基金花费）": total_cost,
        "总收益（卖基金所得）": final_asset,  # 此处按最终资产计算，无中间卖出
        "最终持有基金份额": total_units,
        "最终资产": final_asset,
        "总利润": total_profit,
        "总收益率": total_return_rate,
        "年化收益率": annual_return_rate,
        "买入次数": attempts_times
    }


# （未完成）长短期均值比较：比如30日均值超过90日均值，就买, 不考虑卖
def strategy_based_on_two_mean(df, x=0, y=200, days1=30, days2=90, start_date=None, end_date=None):
    start_date, end_date = process_dates(df, start_date, end_date)
    total_cost = 0
    total_gain = 0
    total_units = 0

    buy_times = 0

    start_index = df.index.searchsorted(start_date)
    end_index = df.index.searchsorted(end_date)

    if start_index < days2:
        start_index = days2

    df_range = df.iloc[start_index:end_index]

    for i in range(len(df_range)):
        current_net_value = df_range['单位净值'].iloc[i]
        short_term_mean = df_range['单位净值'].iloc[i - days1:i].mean()
        long_term_mean = df_range['单位净值'].iloc[i - days2:i].mean()

        # 短期均值超过长期均值，买入
        if short_term_mean < long_term_mean:
            investment_amount = y
            buy_times += 1

            daily_units = investment_amount / current_net_value
            total_units += daily_units
            total_cost += investment_amount

    # 计算最终资产
    if not df_range.empty:
        last_net_value = df_range['单位净值'].iloc[-1]
        final_asset = total_units * last_net_value + total_gain
    else:
        final_asset = 0

    # 计算总收益和收益率
    total_profit = final_asset - total_cost
    total_return_rate = total_profit / total_cost if total_cost != 0 else 0

    # 计算投资天数
    investment_days = (end_date - start_date).days
    # 计算年化收益率
    if total_cost != 0 and investment_days > 0:
        annual_return_rate = ((final_asset / total_cost) ** (365 / investment_days)) - 1
    else:
        annual_return_rate = 0

    return {
        "开始时间": start_date.strftime('%Y-%m-%d'),
        "结束时间": end_date.strftime('%Y-%m-%d'),
        "总投入（买基金花费）": total_cost,
        "总收益（卖基金所得）": total_gain,
        "最终持有基金份额": total_units,
        "最终资产": final_asset,
        "总利润": total_profit,
        "总收益率": total_return_rate,
        "年化收益率": annual_return_rate,
        "买入次数": buy_times,
    }


# （未完成）长短期均值比较：比如30日均值超过90日均值，就买x, 反之，则卖y %
def strategy_based_on_two_mean_2(df, x=200, y=0.5, days1=30, days2=90, period=3, start_date=None, end_date=None):
    start_date, end_date = process_dates(df, start_date, end_date)
    total_cost = 0
    total_gain = 0
    total_units = 0

    buy_times = 0
    sell_times = 0

    start_index = df.index.searchsorted(start_date)
    end_index = df.index.searchsorted(end_date)

    if start_index < days2:
        start_index = days2

    df_range = df.iloc[start_index:end_index]

    # 用于记录是否在 period 日内已经出现过突破或跌破
    last_period_broken_above = False
    last_period_broken_below = False

    for i in range(len(df_range)):
        current_net_value = df_range['单位净值'].iloc[i]
        short_term_mean = df_range['单位净值'].iloc[i - days1:i].mean()
        long_term_mean = df_range['单位净值'].iloc[i - days2:i].mean()

        # 判断是否是 period 日内首次突破
        if i >= days1:
            prev_short_term_mean = df_range['单位净值'].iloc[i - days1 - 1:i - 1].mean()
            prev_long_term_mean = df_range['单位净值'].iloc[i - days2 - 1:i - 1].mean()
            if prev_short_term_mean <= prev_long_term_mean and short_term_mean > long_term_mean:
                if not last_period_broken_above:
                    # period 日内首次突破，买入
                    investment_amount = x
                    buy_times += 1
                    daily_units = investment_amount / current_net_value
                    total_units += daily_units
                    total_cost += investment_amount
                    last_period_broken_above = True
                    last_period_broken_below = False
            elif prev_short_term_mean >= prev_long_term_mean and short_term_mean < long_term_mean:
                if not last_period_broken_below and total_units > 0:
                    # period 日内首次跌破，卖出
                    sell_units = total_units * y
                    sell_amount = sell_units * current_net_value
                    sell_times += 1
                    total_gain += sell_amount
                    total_units -= sell_units
                    last_period_broken_below = True
                    last_period_broken_above = False

        # 每过 period 天重置标志位
        if (i + 1) % period == 0:
            last_period_broken_above = False
            last_period_broken_below = False

    # 计算最终资产
    if not df_range.empty:
        last_net_value = df_range['单位净值'].iloc[-1]
        final_asset = total_units * last_net_value + total_gain
    else:
        final_asset = 0

    # 计算总收益和收益率
    total_profit = final_asset - total_cost
    total_return_rate = total_profit / total_cost if total_cost != 0 else 0

    # 计算投资天数
    investment_days = (end_date - start_date).days
    # 计算年化收益率
    if total_cost != 0 and investment_days > 0:
        annual_return_rate = ((final_asset / total_cost) ** (365 / investment_days)) - 1
    else:
        annual_return_rate = 0

    return {
        "开始时间": start_date.strftime('%Y-%m-%d'),
        "结束时间": end_date.strftime('%Y-%m-%d'),
        "总投入（买基金花费）": total_cost,
        "总收益（卖基金所得）": total_gain,
        "最终持有基金份额": total_units,
        "最终资产": final_asset,
        "总利润": total_profit,
        "总收益率": total_return_rate,
        "年化收益率": annual_return_rate,
        "买入次数": buy_times,
        "卖出次数": sell_times
    }


def print_strategy_result(strategy_name, result):
    logger.info("=" * 36)
    logger.info(f"<{strategy_name}>")
    logger.info(f"开始时间: {result['开始时间']}")
    logger.info(f"结束时间: {result['结束时间']}")
    logger.info(f"总投入（买基金花费）: {result['总投入（买基金花费）']}")
    logger.info(f"年化收益率: {result['年化收益率'] * 100:.2f}%")


